﻿/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Data.SQLite;
using System.Data.Common;
using System.Collections;
using FirebirdSql.Data.FirebirdClient;
using System.IO;
using System.Diagnostics;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;

namespace IvyOrm.Test
{
    [TestClass]

    [DeploymentItem("fbembed.dll")] //Firebird
    [DeploymentItem("ib_util.dll")] //Firebird
    [DeploymentItem("icudt30.dll")] //Firebird
    [DeploymentItem("icuin30.dll")] //Firebird
    [DeploymentItem("icuuc30.dll")] //Firebird
    [DeploymentItem("firebird.msg")] //Firebird

    [DeploymentItem("x86")] //SQLite
    public class DataModificationExtensionTest
    {
        public class SimpleTable
        {
            public string ColumnA;
            public int ColumnB { get; set; }
        }
        #region RecordInsert
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_InvalidArguments()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA TEXT, ColumnB Number)");
                var simpleTable = new SimpleTable { ColumnA = "ValueA", ColumnB = 13 };

                AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordInsert(connection, null));
                AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordInsert((DbConnection)null, simpleTable));

                AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordInsert(connection, new IvyOrmOptions(), null));
                AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordInsert((DbConnection)null, new IvyOrmOptions(), simpleTable));

            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_InvalidArguments_Transaction()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA TEXT, ColumnB Number)");
                var simpleTable = new SimpleTable { ColumnA = "ValueA", ColumnB = 13 };
                using (var transaction = connection.BeginTransaction())
                {
                    AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordInsert((DbTransaction)null, simpleTable));
                    AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordInsert(transaction, null));
                    AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordInsert(new BadDbTransaction(), simpleTable));

                    AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordInsert((DbTransaction)null, new IvyOrmOptions(), simpleTable));
                    AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordInsert(transaction, new IvyOrmOptions(), null));
                    AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordInsert(new BadDbTransaction(), new IvyOrmOptions(), simpleTable));

                }
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_SimpleTable()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA TEXT, ColumnB Number)");
                var simpleTable = new SimpleTable { ColumnA = "ValueA", ColumnB = 13 };
                connection.RecordInsert(simpleTable);


                //Regular Method
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = "select ColumnA, ColumnB from SimpleTable";
                    using (var reader = command.ExecuteReader())
                    {
                        reader.Read();
                        Assert.AreEqual("ValueA", reader["ColumnA"]);
                        Assert.AreEqual(13, Convert.ToInt32(reader["ColumnB"]));
                    }
                }
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_SimpleTable_Transaction()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA TEXT, ColumnB Number)");
                using (var transaction = connection.BeginTransaction())
                {
                    var simpleTable = new SimpleTable { ColumnA = "ValueA", ColumnB = 13 };
                    transaction.RecordInsert(simpleTable);


                    //Regular Method
                    using (var command = connection.CreateCommand())
                    {
                        command.CommandText = "select ColumnA, ColumnB from SimpleTable";
                        using (var reader = command.ExecuteReader())
                        {
                            reader.Read();
                            Assert.AreEqual("ValueA", reader["ColumnA"]);
                            Assert.AreEqual(13, Convert.ToInt32(reader["ColumnB"]));
                        }
                    }
                }
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_Overloads()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA TEXT, ColumnB Number)");
                var simpleTable = new SimpleTable { ColumnA = "ValueA", ColumnB = 13 };

                connection.RecordInsert(simpleTable);
                Assert.AreEqual(1, connection.ValueSingle<int>("select count(*) from SimpleTable"));

                connection.RecordInsert(new IvyOrmOptions(), simpleTable);
                Assert.AreEqual(2, connection.ValueSingle<int>("select count(*) from SimpleTable"));

            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_Overloads_Transaction()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA TEXT, ColumnB Number)");

                using (var transaction = connection.BeginTransaction())
                {
                    var simpleTable = new SimpleTable { ColumnA = "ValueA", ColumnB = 13 };

                    transaction.RecordInsert(simpleTable);
                    Assert.AreEqual(1, connection.ValueSingle<int>("select count(*) from SimpleTable"));

                    transaction.RecordInsert(new IvyOrmOptions(), simpleTable);
                    Assert.AreEqual(2, connection.ValueSingle<int>("select count(*) from SimpleTable"));

                }
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_SimpleTable_RecordSingle()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA TEXT, ColumnB Number)");
                var simpleTable = new SimpleTable { ColumnA = "ValueA", ColumnB = 13 };
                connection.RecordInsert(simpleTable);

                var simpleTableReturned = connection.RecordSingle<SimpleTable>("select * from SimpleTable");
                Assert.AreEqual(simpleTable.ColumnA, simpleTableReturned.ColumnA);
                Assert.AreEqual(simpleTable.ColumnB, simpleTableReturned.ColumnB);
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_UppercaseAndLowercaseIdentifiers()
        {
            var simpleTable = new SimpleTable { ColumnA = "ValueA", ColumnB = 13 };

            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA TEXT, ColumnB Number)");

                using (var command = connection.CreateCommand())
                {   //SQLite is not case sensitive so all of he following commands should work
                    DataModificationExtension.recordInsertExecute(command, new IvyOrmOptions { DbProviderFactory = SQLiteFactory.Instance, ModificationOptions = ModificationOptions.UppercaseIdentifiers }, simpleTable);
                    Assert.IsTrue(command.CommandText.Contains("SIMPLETABLE"));
                    Assert.IsFalse(command.CommandText.Contains("SimpleTable"));
                }
                using (var command = connection.CreateCommand())
                {
                    DataModificationExtension.recordInsertExecute(command, new IvyOrmOptions { DbProviderFactory = SQLiteFactory.Instance, ModificationOptions = ModificationOptions.LowercaseIdentifiers }, simpleTable);
                    Assert.IsTrue(command.CommandText.Contains("simpletable"));
                    Assert.IsFalse(command.CommandText.Contains("SimpleTable"));
                }
                using (var command = connection.CreateCommand())
                {
                    DataModificationExtension.recordInsertExecute(command, new IvyOrmOptions { DbProviderFactory = SQLiteFactory.Instance, ModificationOptions = ModificationOptions.None }, simpleTable);
                    Assert.IsTrue(command.CommandText.Contains("SimpleTable"));
                }
            }
        }

        [Table("SimpleTable")]
        public class NonPublicSetter
        {
            public void SetColumnA(string value)
            {
                m_ColumnA = value;
            }
            private string m_ColumnA;
            
            public string ColumnA
            {
                //Because there is no public setter it will be ignored by IvyOrm
                get { return m_ColumnA; }
            }
            public string ColumnB { get; set; }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_ReadOnlyColumn()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA TEXT, ColumnB TEXT)");
                var row = new NonPublicSetter();
                row.SetColumnA("ValueA");
                row.ColumnB = "ValueB";
                connection.RecordInsert(row);
                
                //Regular Method
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = "select ColumnA, ColumnB from SimpleTable";
                    using (var reader = command.ExecuteReader())
                    {
                        reader.Read();
                        Assert.IsTrue(reader["ColumnA"] == null || 
                                      reader["ColumnA"] == DBNull.Value);
                        Assert.AreEqual("ValueB", reader["ColumnB"]);
                    }
                }

                //Alt Method
                var row2 = connection.RecordSingle<NonPublicSetter>("select * from SimpleTable");
                Assert.AreEqual(null, row2.ColumnA);
                Assert.AreEqual("ValueB", row2.ColumnB);
            }
        }


        [Table("SimpleTable")]
        public class IncorrectNonPublicSetter
        {
            public void SetColumnA(string value)
            {
                m_ColumnA = value;
            }
            private string m_ColumnA;

            [Column]
            public string ColumnA
            {
                //Because there is no public setter it will be ignored by IvyOrm
                get { return m_ColumnA; }
            }
            public string ColumnB;
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_IncorrectNonPublicSetter()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA TEXT, ColumnB TEXT)");
                var row = new IncorrectNonPublicSetter();
                row.SetColumnA("ValueA");
                row.ColumnB = "ValueB";
                AssertB.ThrowsException<IvyOrmException>(() => connection.RecordInsert(row));
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_ExcludeColumnsTable()
        {
            var row = CompilerService.CreateInstanceFromCode(@"
                        [Table(""SimpleTable"")]
                        public class ExcludeColumnsTable
                        {
                            [ExcludeColumn]
                            public string ColumnB;
                        }
                        ");

            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA TEXT, ColumnB TEXT)");
                row.ColumnB = "ValueB";
                AssertB.ThrowsException<IvyOrmException>(() => connection.RecordInsert((object)row));
            }
        }

        [Table("SimpleTable")]
        public class ReturnKeyValueOnInsert
        {
            [PrimaryKey(PrimaryKeyOptions.ReturnKeyValueOnInsert)]
            public int? ColumnA { get; set; }
            public string ColumnB;
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_ReturnPrimaryKey()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER PRIMARY KEY, ColumnB varchar(200))");
                var row1 = new ReturnKeyValueOnInsert();
                row1.ColumnB = "Value1";

                var row2 = new ReturnKeyValueOnInsert();
                row2.ColumnB = "Value2";

                connection.RecordInsert(row1);
                connection.RecordInsert(row2);

                Assert.AreNotEqual(row1.ColumnA, row2.ColumnA);

                //Verify they made it to the database
                var row1_returned = connection.RecordSingle<ReturnKeyValueOnInsert>("select * from simpletable where ColumnA = @0", 1);
                var row2_returned = connection.RecordSingle<ReturnKeyValueOnInsert>("select * from simpletable where ColumnA = @0", 2);
                Assert.AreEqual(row1_returned.ColumnA, 1);
                Assert.AreEqual(row2_returned.ColumnA, 2);
            }
        }

        [TestMethod]
        [TestCategory("Firebird")]
        public void RecordInsert_ReturnPrimaryKey_FireBird()
        {
            //SQLite does not support returning null as the primary key
            var parameters = new FbConnectionStringBuilder();
            parameters.Add("User", "SYSDBA");
            parameters.Add("Password", "masterkey");
            parameters.Database = Path.GetFullPath(Path.ChangeExtension(Path.GetRandomFileName(), ".fdb"));
            parameters.ServerType = FbServerType.Embedded;
            FbConnection.CreateDatabase(parameters.ConnectionString);
            using (var connection = new FbConnection(parameters.ConnectionString))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER PRIMARY KEY, ColumnB varchar(200))");
                connection.ExecuteNonQuery("CREATE GENERATOR gen_t1_id;");
                connection.ExecuteNonQuery("SET GENERATOR gen_t1_id TO 0;");
                connection.ExecuteNonQuery(
                            @"
                            CREATE TRIGGER T1_BI FOR SimpleTable
                            ACTIVE BEFORE INSERT POSITION 0
                            AS
                            BEGIN
                            if (NEW.ColumnA is NULL) then NEW.ColumnA = GEN_ID(GEN_T1_ID, 1);
                            END");

                var row1 = new ReturnKeyValueOnInsert();
                row1.ColumnB = "Value1";

                var row2 = new ReturnKeyValueOnInsert();
                row2.ColumnB = "Value2";

                connection.RecordInsert(row1);
                connection.RecordInsert(row2);

                Assert.AreNotEqual(row1.ColumnA, row2.ColumnA);
            }
        }

        [TestMethod]
        [DeploymentItem("fbembed")]
        [TestCategory("Firebird")]
        public void RecordInsert_ReturnsPrimaryKeyNull_FireBird()
        {
            //Would have done this with SQLite however SQLite does not support returning null as the primary key
            var parameters = new FbConnectionStringBuilder();
            parameters.Add("User", "SYSDBA");
            parameters.Add("Password", "masterkey");
            parameters.Database = Path.GetFullPath(Path.ChangeExtension(Path.GetRandomFileName(), ".fdb"));
            parameters.ServerType = FbServerType.Embedded;
            FbConnection.CreateDatabase(parameters.ConnectionString);
            using (var connection = new FbConnection(parameters.ConnectionString))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB varchar(200))");

                var row1 = new ReturnKeyValueOnInsert();
                row1.ColumnA = 12;
                row1.ColumnB = "Value1";

                var row2 = new ReturnKeyValueOnInsert();
                row2.ColumnA = 13;
                row2.ColumnB = "Value2";

                connection.RecordInsert(row1);
                connection.RecordInsert(row2);

                Assert.AreEqual(null, row1.ColumnA);
                Assert.AreEqual(null, row2.ColumnA);
            }
        }


        [Table("SimpleTable")]
        public class RecordInsert_ReturnPrimaryKeyField_Class
        {
            [PrimaryKey(PrimaryKeyOptions.ReturnKeyValueOnInsert)]
            public int? ColumnA;
            public string ColumnB;
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_ReturnPrimaryKeyField()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER PRIMARY KEY, ColumnB varchar(200))");
                var row1 = new RecordInsert_ReturnPrimaryKeyField_Class();
                row1.ColumnB = "Value1";

                var row2 = new RecordInsert_ReturnPrimaryKeyField_Class();
                row2.ColumnB = "Value2";

                connection.RecordInsert(row1);
                connection.RecordInsert(row2);

                Assert.AreNotEqual(row1.ColumnA, row2.ColumnA);
            }
        }

        [Table("SimpleTable")]
        public class RecordInsert_ReturnPrimaryKeyField_NotSupported_Class
        {
            [PrimaryKey(PrimaryKeyOptions.ReturnKeyValueOnInsert)]
            public int? ColumnA;
            [PrimaryKey(PrimaryKeyOptions.ReturnKeyValueOnInsert)]
            public int? ColumnB;
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_ReturnPrimaryKeyField_NotSupported()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER PRIMARY KEY, ColumnB varchar(200))");
                var row1 = new RecordInsert_ReturnPrimaryKeyField_NotSupported_Class();

                AssertB.ThrowsException<NotSupportedException>(() => connection.RecordInsert(row1));
            }
        }


        [Table("SimpleTable")]
        public class RecordInsert_ReturnMultiplePrimaryKeyFieldNotSupported_Firebird_Class
        {
            [PrimaryKey(PrimaryKeyOptions.ReturnKeyValueOnInsert)]
            public int? ColumnA;
            [PrimaryKey(PrimaryKeyOptions.ReturnKeyValueOnInsert)]
            public int? ColumnB;
        }
        [TestMethod]
        [TestCategory("Firebird")]
        public void RecordInsert_ReturnMultiplePrimaryKeyFieldNotSupported_Firebird()
        {
            var parameters = new FbConnectionStringBuilder();
            parameters.Add("User", "SYSDBA");
            parameters.Add("Password", "masterkey");
            parameters.Database = Path.GetFullPath(Path.ChangeExtension(Path.GetRandomFileName(), ".fdb"));
            parameters.ServerType = FbServerType.Embedded;
            FbConnection.CreateDatabase(parameters.ConnectionString);
            using (var connection = new FbConnection(parameters.ConnectionString))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER PRIMARY KEY, ColumnB INTEGER)");

                var row1 = new RecordInsert_ReturnMultiplePrimaryKeyFieldNotSupported_Firebird_Class();
                AssertB.ThrowsException<NotSupportedException>(() => connection.RecordInsert(row1));
            }
        }

        [Table("SimpleTable")]
        public class RecordInsert_UnknownProvider_Class
        {
            [PrimaryKey(PrimaryKeyOptions.ReturnKeyValueOnInsert)]
            public int? ColumnA;
            public int? ColumnB;
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_UnknownProvider()
        {
            using (var connection = new MockProvider.MockConnection())
            {
                AssertB.ThrowsException<NotSupportedException>(() => connection.RecordInsert(new RecordInsert_UnknownProvider_Class()));
            }
        }

        [Table("SimpleTable")]
        public class RecordInsert_NonReturnPrimaryKeyField_Class
        {
            [PrimaryKey]
            public int? ColumnA;
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_NonReturnPrimaryKeyField()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB varchar(200))");
                var row1 = new RecordInsert_NonReturnPrimaryKeyField_Class();
                row1.ColumnA = 12;
                connection.RecordInsert(row1);

                Assert.AreEqual(12, row1.ColumnA);
            }
        }


        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordInsert_Logging()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                string lastLog = null;
                var options = new IvyOrmOptions();
                options.LoggingFunction = (l, s, e) => lastLog = s;
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA TEXT, ColumnB Number)");
                var simpleTable = new SimpleTable { ColumnA = "ValueA", ColumnB = 13 };
                connection.RecordInsert(options, simpleTable);
                Debug.Assert(lastLog != null && lastLog.ToUpperInvariant().Contains("insert into".ToUpperInvariant()));
            }
        }
        #endregion

        #region RecordUpdate
        [Table("SimpleTable")]
        public class RecordUpdate_SimpleTable_Class
        {
            [PrimaryKey]
            public int ColumnA { get; set; }
            public string ColumnB { get; set; }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordUpdate_SimpleTable()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER PRIMARY KEY, ColumnB varchar(200))");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 3, "ValueA");
                Assert.AreEqual("ValueA", connection.ValueSingle<string>("select ColumnB from SimpleTable where ColumnA=@0", 3));

                var row1 = new RecordUpdate_SimpleTable_Class();
                row1.ColumnA = 3;
                row1.ColumnB = "ValueB";
                connection.RecordUpdate(row1);
                Assert.AreEqual("ValueB", connection.ValueSingle<string>("select ColumnB from SimpleTable where ColumnA=@0", 3));
            }
        }

        [Table("SimpleTable")]
        public class RecordUpdate_SimpleTable_Transaction_Class
        {
            [PrimaryKey]
            public int ColumnA { get; set; }
            public string ColumnB { get; set; }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordUpdate_SimpleTable_Transaction()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER PRIMARY KEY, ColumnB varchar(200))");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 3, "ValueA");
                Assert.AreEqual("ValueA", connection.ValueSingle<string>("select ColumnB from SimpleTable where ColumnA=@0", 3));
                using (var transaction = connection.BeginTransaction())
                {
                    var row1 = new RecordUpdate_SimpleTable_Transaction_Class();
                    row1.ColumnA = 3;
                    row1.ColumnB = "ValueB";
                    transaction.RecordUpdate(row1);
                    Assert.AreEqual("ValueB", connection.ValueSingle<string>("select ColumnB from SimpleTable where ColumnA=@0", 3));
                }
            }
        }


        [Table("SimpleTable")]
        public class RecordUpdate_MuliplePrimaryKeys_Class
        {
            [PrimaryKey]
            public int ColumnA { get; set; }
            [PrimaryKey]
            public int ColumnB { get; set; }
            public string ColumnC { get; set; }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordUpdate_MuliplePrimaryKeys()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB INTEGER, ColumnC varchar(200), PRIMARY KEY (ColumnA, ColumnB))");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB, ColumnC) values (@0, @1, @2)", 1, 4, "ValueA");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB, ColumnC) values (@0, @1, @2)", 1, 5, "ValueB");
                Assert.AreEqual("ValueB", connection.ValueSingle<string>("select ColumnC from SimpleTable where ColumnA=@0 and ColumnB=@1", 1, 5));

                var row1 = new RecordUpdate_MuliplePrimaryKeys_Class();
                row1.ColumnA = 1;
                row1.ColumnB = 5;
                row1.ColumnC = "ValueC";
                connection.RecordUpdate(row1);
                Assert.AreEqual("ValueC", connection.ValueSingle<string>("select ColumnC from SimpleTable where ColumnA=@0 and ColumnB=@1", 1, 5));
                Assert.AreEqual("ValueA", connection.ValueSingle<string>("select ColumnC from SimpleTable where ColumnA=@0 and ColumnB=@1", 1, 4));
            }
        }

        [Table("SimpleTable")]
        public class RecordUpdate_MulipleColumnsToUpdate_Class
        {
            [PrimaryKey]
            public int ColumnA { get; set; }
            
            public string ColumnB { get; set; }
            public string ColumnC { get; set; }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordUpdate_MulipleColumnsToUpdate()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB TEXT, ColumnC TEXT, PRIMARY KEY (ColumnA))");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB, ColumnC) values (@0, @1, @2)", 7, "ValueA", "ValueB");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB, ColumnC) values (@0, @1, @2)", 8, "ValueC", "ValueD");
                Assert.AreEqual("ValueC", connection.ValueSingle<string>("select ColumnB from SimpleTable where ColumnA=@0", 8));
                Assert.AreEqual("ValueD", connection.ValueSingle<string>("select ColumnC from SimpleTable where ColumnA=@0", 8));

                var row1 = new RecordUpdate_MulipleColumnsToUpdate_Class();
                row1.ColumnA = 8;
                row1.ColumnB = "ValueE";
                row1.ColumnC = "ValueF";
                connection.RecordUpdate(row1);

                Assert.AreEqual("ValueE", connection.ValueSingle<string>("select ColumnB from SimpleTable where ColumnA=@0", 8));
                Assert.AreEqual("ValueF", connection.ValueSingle<string>("select ColumnC from SimpleTable where ColumnA=@0", 8));
            }
        }



        [Table("SimpleTable")]
        public class RecordUpdate_ArgumentNullExceptions_SimpleTable
        {
            [PrimaryKey]
            public int ColumnA { get; set; }
            public string ColumnB { get; set; }
        }
        [Table("SimpleTable")]
        public class RecordUpdate_ArgumentNullExceptions_NoPrimaryKey
        {
            public int ColumnA { get; set; }
            public string ColumnB { get; set; }
        }
        [Table("SimpleTable")]
        public class RecordUpdate_ArgumentNullExceptions_NoUpdatableColumns
        {
            [PrimaryKey]
            public int ColumnA { get; set; }
            [PrimaryKey]
            public string ColumnB { get; set; }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordUpdate_ArgumentNullExceptions()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                var row = new RecordUpdate_ArgumentNullExceptions_SimpleTable();
                AssertB.ThrowsException<ArgumentNullException>(() => DataModificationExtension.RecordUpdate(connection, (object)null), "Did not alert on record null");
                AssertB.ThrowsException<ArgumentNullException>(() => DataModificationExtension.RecordUpdate((DbConnection)null, new IvyOrmOptions(), row), "Did not alert on connection null");
                AssertB.ThrowsException<NotSupportedException>(() => DataModificationExtension.RecordUpdate(connection, new IvyOrmOptions(), new RecordUpdate_ArgumentNullExceptions_NoUpdatableColumns()), "Did not alert on RecordUpdate_ArgumentNullExceptions_NoUpdatableColumns");

            }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordUpdate_ArgumentNullExceptions_Transaction()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                using (var transaction = connection.BeginTransaction())
                {
                    var row = new RecordUpdate_ArgumentNullExceptions_SimpleTable();

                    AssertB.ThrowsException<ArgumentNullException>(() => DataModificationExtension.RecordUpdate((DbTransaction)null, row));
                    AssertB.ThrowsException<ArgumentNullException>(() => DataModificationExtension.RecordUpdate((DbTransaction)null, new IvyOrmOptions(), row));
                    AssertB.ThrowsException<ArgumentNullException>(() => DataModificationExtension.RecordUpdate(transaction, new IvyOrmOptions(), (object)null));
                    AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordUpdate(new BadDbTransaction(), new IvyOrmOptions(), row));
                    AssertB.ThrowsException<NotSupportedException>(() => DataModificationExtension.RecordUpdate(transaction, new IvyOrmOptions(), new RecordUpdate_ArgumentNullExceptions_NoUpdatableColumns()));
                    AssertB.ThrowsException<NotSupportedException>(() => DataModificationExtension.RecordUpdate(transaction, new IvyOrmOptions(), new RecordUpdate_ArgumentNullExceptions_NoPrimaryKey()));
                }
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordUpdate_Overloads()
        {
            var row = CompilerService.CreateInstanceFromCode(@"
                        [Table(""SimpleTable"")]
                        public class RecordUpdate_Overloads_SimpleTable
                        {
                            [PrimaryKey]
                            public int ColumnA { get; set; }
                            public string ColumnB { get; set; }
                        }
                        ");

            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER PRIMARY KEY, ColumnB varchar(200))");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, "ValueA");


                row.ColumnA = 1;
                row.ColumnB = "ValueA";

                connection.RecordUpdate((object)row);
                connection.RecordUpdate(new IvyOrmOptions(), (object)row);

                using (var transaction = connection.BeginTransaction())
                {
                    transaction.RecordUpdate((object)row);
                    transaction.RecordUpdate(new IvyOrmOptions(), (object)row);
                }
            }
        }

        [Table("SimpleTable")]
        public class RecordUpdate_NoRecordsUpdated_SimpleTable
        {
            [PrimaryKey]
            public int ColumnA { get; set; }
            public string ColumnB { get; set; }
        }
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordUpdate_NoRecordsUpdated()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER PRIMARY KEY, ColumnB varchar(200))");

                var row = new RecordUpdate_NoRecordsUpdated_SimpleTable();
                row.ColumnA = 3; //this record does not exist
                AssertB.ThrowsException<IvyOrmException>(() => connection.RecordUpdate(new IvyOrmOptions { ModificationOptions = IvyOrm.ModificationOptions.None },  row));
            }


            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER PRIMARY KEY, ColumnB varchar(200))");

                var row = new RecordUpdate_NoRecordsUpdated_SimpleTable();
                row.ColumnA = 3; //this record does not exist

                //When DoNotThrowExceptionOnNoRecordsUpdated is set no exceptions thrown
                connection.RecordUpdate(new IvyOrmOptions { ModificationOptions = ModificationOptions.DoNotThrowExceptionOnNoRecordsUpdated }, row);
            }
        }


        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordUpdate_NullPrimaryKey()
        {
            var code = @"public class SimpleTable
                            {
                                [PrimaryKey]
                                public int? ColumnA { get; set; }
                                public string ColumnB { get; set; }
                            }";

            //Connection
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", null, "Row1");

                var obj = CompilerService.CreateInstanceFromCode(code);
                obj.ColumnB = "Row1b";
                connection.RecordUpdate((object)obj);

                Assert.AreEqual("Row1b", connection.ValueSingle<string>("select ColumnB from SimpleTable where ColumnA is null"));
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordUpdate_DbNullPrimaryKey()
        {
            var code = @"public class SimpleTable
                            {
                                [PrimaryKey]
                                public object ColumnA { get; set; }
                                public string ColumnB { get; set; }
                            }";

            //Connection
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", null, "Row1");

                var obj = CompilerService.CreateInstanceFromCode(code);
                obj.ColumnA = DBNull.Value;
                obj.ColumnB = "Row1b";
                connection.RecordUpdate((object)obj);

                Assert.AreEqual("Row1b", connection.ValueSingle<string>("select ColumnB from SimpleTable where ColumnA is null"));
            }
        }


        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordUpdate_Logging()
        {
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                string lastLog = null;
                var options = new IvyOrmOptions();
                options.LoggingFunction = (l, s, e) => lastLog = s;

                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER PRIMARY KEY, ColumnB varchar(200))");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 3, "ValueA");
                Assert.AreEqual("ValueA", connection.ValueSingle<string>("select ColumnB from SimpleTable where ColumnA=@0", 3));

                var row1 = new RecordUpdate_SimpleTable_Class();
                row1.ColumnA = 3;
                row1.ColumnB = "ValueB";
                connection.RecordUpdate(options, row1);

                Assert.IsTrue(lastLog != null && lastLog.ToUpperInvariant().Contains("update".ToUpperInvariant()));
                Assert.IsTrue(lastLog != null && lastLog.ToUpperInvariant().Contains("simpletable".ToUpperInvariant()));
            }
        }
        #endregion

        #region RecordDelete
        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordDelete_SimpleTable()
        {
            var code = @"public class SimpleTable
                            {
                                [PrimaryKey]
                                public int ColumnA { get; set; }
                                public string ColumnB { get; set; }
                            }";

            //Connection
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, "Row1");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 2, "Row2");
                var recordCount = connection.ValueSingle<int>("select count(*) from SimpleTable");
                Assert.AreEqual(2, recordCount);


                var obj = CompilerService.CreateInstanceFromCode(code);
                obj.ColumnA = 2;
                connection.RecordDelete((object)obj);

                recordCount = connection.ValueSingle<int>("select count(*) from SimpleTable");
                Assert.AreEqual(1, recordCount);
            }


            //Transaction
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, "Row1");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 2, "Row2");
                var recordCount = connection.ValueSingle<int>("select count(*) from SimpleTable");
                Assert.AreEqual(2, recordCount);

                using (var transaction = connection.BeginTransaction())
                {

                    var obj = CompilerService.CreateInstanceFromCode(code);
                    obj.ColumnA = 2;
                    transaction.RecordDelete((object)obj);

                    recordCount = transaction.ValueSingle<int>("select count(*) from SimpleTable");
                    Assert.AreEqual(1, recordCount);
                }
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordDelete_ArgumentException()
        {
            var code = @"public class SimpleTable
                            {
                                [PrimaryKey]
                                public int ColumnA { get; set; }
                                public string ColumnB { get; set; }
                            }";

            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, "Row1");
                
                
                var obj = CompilerService.CreateInstanceFromCode(code);

                AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordDelete((DbConnection)null, obj));
                AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordDelete(connection, (object)null));

                AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordDelete((DbConnection)null, new IvyOrmOptions(), obj));
                AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordDelete(connection, new IvyOrmOptions(), (object)null));

                using (var transaction = connection.BeginTransaction())
                {

                    AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordDelete((DbTransaction)null, (object)obj));
                    AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordDelete(transaction, (object)null));
                    AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordDelete(new BadDbTransaction(), (object)obj));

                    AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordDelete((DbTransaction)null, new IvyOrmOptions(), (object)obj));
                    AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordDelete(transaction, new IvyOrmOptions(), (object)null));
                    AssertB.ThrowsException<ArgumentException>(() => DataModificationExtension.RecordDelete(new BadDbTransaction(), new IvyOrmOptions(), (object)obj));

                }

            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordDelete_NoRecordsDelete()
        {
            var code = @"public class SimpleTable
                            {
                                [PrimaryKey]
                                public int ColumnA { get; set; }
                                public string ColumnB { get; set; }
                            }";

            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, "Row1");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, "Row2");
                var recordCount = connection.ValueSingle<int>("select count(*) from SimpleTable");
                Assert.AreEqual(2, recordCount);


                var obj = CompilerService.CreateInstanceFromCode(code);
                obj.ColumnA = 2;
                AssertB.ThrowsException<IvyOrmException>(() => connection.RecordDelete((object)obj));

                //Should not throw exeption when ModificationOptions.DoNotThrowExceptionOnNoRecordsUpdated is set
                connection.RecordDelete(new IvyOrmOptions { ModificationOptions = ModificationOptions.DoNotThrowExceptionOnNoRecordsUpdated }, (object)obj);
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordDelete_NoPrimaryKey()
        {
            var code = @"public class SimpleTable
                            {
                                public int ColumnA { get; set; }
                                public string ColumnB { get; set; }
                            }";

            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, "Row1");


                var obj = CompilerService.CreateInstanceFromCode(code);
                obj.ColumnA = 1;
                AssertB.ThrowsException<NotSupportedException>(() => connection.RecordDelete((object)obj));
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordDelete_CompositKey()
        {
            var code = @"public class SimpleTable
                            {
                                [PrimaryKey]
                                public int ColumnA { get; set; }
                                [PrimaryKey]
                                public int ColumnB { get; set; }
                            }";

            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB INTEGER)");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, 1);
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, 2);
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 2, 1);
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 2, 2);
                var recordCount = connection.ValueSingle<int>("select count(*) from SimpleTable");
                Assert.AreEqual(4, recordCount);


                var obj = CompilerService.CreateInstanceFromCode(code);
                obj.ColumnA = 1;
                obj.ColumnB = 2;
                connection.RecordDelete((object)obj);

                recordCount = connection.ValueSingle<int>("select count(*) from SimpleTable");
                Assert.AreEqual(3, recordCount);
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordDelete_Overloads()
        {
            var code = @"public class SimpleTable
                            {
                                [PrimaryKey]
                                public int ColumnA { get; set; }
                                public string ColumnB { get; set; }
                            }";

            //Connection
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, "Row1");
                Assert.AreEqual(1, connection.ValueSingle<int>("select count(*) from SimpleTable"));
                var obj = CompilerService.CreateInstanceFromCode(code);
                obj.ColumnA = 1;

                connection.RecordDelete((object)obj);
                Assert.AreEqual(0, connection.ValueSingle<int>("select count(*) from SimpleTable"));
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, "Row1");

                connection.RecordDelete(new IvyOrmOptions(), (object)obj);
                Assert.AreEqual(0, connection.ValueSingle<int>("select count(*) from SimpleTable"));
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, "Row1");


                using (var transaction = connection.BeginTransaction())
                {
                    transaction.RecordDelete((object)obj);
                    Assert.AreEqual(0, transaction.ValueSingle<int>("select count(*) from SimpleTable"));
                    transaction.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, "Row1");

                    transaction.RecordDelete(new IvyOrmOptions(), (object)obj);
                    Assert.AreEqual(0, transaction.ValueSingle<int>("select count(*) from SimpleTable"));
                    transaction.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, "Row1");
                    
                }
            }
        }

        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordDelete_NullPrimaryKey()
        {
            var code = @"public class SimpleTable
                            {
                                [PrimaryKey]
                                public int? ColumnA { get; set; }
                                public string ColumnB { get; set; }
                            }";

            //Connection
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", null, "Row1");

                var obj = CompilerService.CreateInstanceFromCode(code);

                connection.RecordDelete((object)obj);

                Assert.AreEqual(0, connection.ValueSingle<int>("select count(*) from SimpleTable"));
            }
        }


        [TestMethod]
        [TestCategory("SQLite")]
        public void RecordDelete_Logging()
        {
            var code = @"public class SimpleTable
                            {
                                [PrimaryKey]
                                public int ColumnA { get; set; }
                                public string ColumnB { get; set; }
                            }";

            //Connection
            using (var connection = new SQLiteConnection("Data Source=:memory:;Version=3;New=True;"))
            {
                connection.Open();
                connection.ExecuteNonQuery("create table SimpleTable (ColumnA INTEGER, ColumnB TEXT)");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 1, "Row1");
                connection.ExecuteNonQuery("insert into SimpleTable (ColumnA, ColumnB) values (@0, @1)", 2, "Row2");
                var recordCount = connection.ValueSingle<int>("select count(*) from SimpleTable");
                Assert.AreEqual(2, recordCount);


                var obj = CompilerService.CreateInstanceFromCode(code);
                obj.ColumnA = 2;


                string lastLog = null;
                var options = new IvyOrmOptions();
                options.LoggingFunction = (l, s, e) => lastLog = s;

                connection.RecordDelete(options, (object)obj);

                Assert.IsTrue(lastLog != null && lastLog.ToUpperInvariant().Contains("delete from".ToUpperInvariant()));
                Assert.IsTrue(lastLog != null && lastLog.ToUpperInvariant().Contains("simpletable".ToUpperInvariant()));
            }
        }

        #endregion
    }
}

